/*
 * Copyright 2008 aileron.cc, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package cc.aileron.commons.accessor.factory;

import cc.aileron.commons.accessor.PojoAccessor;
import cc.aileron.commons.accessor.PojoAccessorConvertor;
import cc.aileron.commons.accessor.PojoAccessorConvertorFactory;
import cc.aileron.commons.accessor.PojoAccessorFactory;
import cc.aileron.commons.accessor.properties.PojoPropertiesChainAccessor;

/**
 * PojoAccessorImpl
 * @author Aileron
 *
 * @param <T>
 */
class PojoAccessorImpl <T> implements PojoAccessor<T>
{
    @Override
    public String toString()
    {
        return this.pojo.toTarget().toString();
    }
    
    /*
     * (非 Javadoc)
     * @see cc.aileron.commons.accessor.PojoAccessor#getNumber(java.lang.String)
     */
    public Number getNumber(String name)
    {
        try
        {
            return Number.class.cast(getObject(name));
        }
        catch(ClassCastException e)
        {
            return 0;
        }
    }
    
    /*
     * (非 Javadoc)
     * @see cc.aileron.commons.accessor.PojoAccessor#getBoolean(java.lang.String)
     */
    public boolean getBoolean(String name)
    {
        final int last = name.lastIndexOf('.');
        if(last==-1)
        {
            return defCompare(pojo, name);
        }
        return enumCompare(pojo, name, last);
    }
    
    /*
     * (非 Javadoc)
     * @see cc.aileron.commons.accessor.PojoAccessor#getList(java.lang.String)
     */
    public Iterable<PojoAccessor<?>> getList(String name)
    {
        return new PojoAccessorIterator( aFactory, getObject(name) );
    }
    
    /*
     * (非 Javadoc)
     * @see cc.aileron.commons.accessor.PojoAccessor#getObject(java.lang.String)
     */
    public Object getObject(String name)
    {
        return pojo.getObjectChainAccess(name);
    }
    
    /*
     * (非 Javadoc)
     * @see cc.aileron.commons.accessor.PojoAccessor#getString(java.lang.String)
     */
    public String getString(final String name)
    {
        final PojoAccessorConvertor<Object,Object> convertor;
        final String key ;
        if(name.indexOf('@')==0)
        {
            final String[] token = name.substring(1).split("@");
            key = token[1];
            convertor = cFactory.getInstance(token[0]);
        }
        else
        {
            key = name;
            convertor = null;
        }
        final Object object = getObject(key);
        if(object==null)
        {
            return "";
        }
        
        if(convertor==null)
        {
            return object.toString();
        }
        
        return convertor.convert(object).toString();
    }

    /*
     * (非 Javadoc)
     * @see cc.aileron.commons.accessor.PojoAccessor#set(java.lang.String, java.lang.Object)
     */
    public void set(String name, Object value)
    {
        final PojoAccessorConvertor<Object,Object> convertor;
        final String key ;
        if(name.indexOf('@')==0)
        {
            final String[] token = name.substring(1).split("@");
            key = token[1];
            convertor = cFactory.getInstance(token[0]);
        }
        else
        {
            key = name;
            convertor = null;
        }
        if(convertor==null)
        {
            pojo.setObjectChainAccess(key, value);
        }
        else
        {
            pojo.setObjectChainAccess(key, convertor.convert(value));
        }
    }
    
    /*
     * (非 Javadoc)
     * @see cc.aileron.commons.accessor.PojoAccessor#toTarget()
     */
    public T toTarget()
    {
        return pojo.toTarget();
    }
    
    /**
     * enum object　の場合に カンマ区切りの最終端の名前と enum.name() が一致するか如何かを
     * 比較する。
     * 
     * enum object で無い場合は、defCompareします
     * @param name
     * @return
     */
    private boolean enumCompare(final PojoPropertiesChainAccessor<?> accessor, final String name, final int last)
    {
        final Object object = accessor.getObjectChainAccess( name.substring(0, last) );
        if(object==null)
        {
            return false;
        }
        final String type = name.substring(last+1, name.length());
        if(! object.getClass().isEnum())
        {
            return defCompare(instanceManager.newChainAccessor(instanceManager.newProperties(object)), type);
        }
        return ((Enum<?>)object).name().equals(type);
    }
    
    /**
     * object の存在および、 boolean 値を返す
     * @param accessor
     * @param name
     * @return
     */
    private boolean defCompare(final PojoPropertiesChainAccessor<?> accessor, final String name)
    {
        final Object target = accessor.getObjectChainAccess(name);
        if(target==null)
        {
            return false;
        }
        if(target instanceof Boolean)
        {
            return (Boolean) target;
        }
        if(Number.class.isAssignableFrom(target.getClass()))
        {
            final Number n = (Number) target;
            if(n.intValue()==0)
            {
                return false;
            }
        }
        return true;
    }   
    
    /**
     * constract
     * @param factory 
     * @param pojo
     */
    public PojoAccessorImpl(
            final PojoAccessorFactory factory,
            final PojoPropertiesChainAccessor<T> pojo)
    {
        this.aFactory = factory;
        this.pojo = pojo;
        this.instanceManager = factory.getInstanceManager();
        this.cFactory = instanceManager.getConvertorFactory();
    }   
    
    /**
     * instance-manager
     */
    private final PojoAccessorInstanceManager instanceManager;
    
    /**
     * pojo
     */
    private final PojoPropertiesChainAccessor<T> pojo;
    
    /**
     * factory
     */
    private final PojoAccessorFactory aFactory;
    
    /**
     * pool
     */
    private final PojoAccessorConvertorFactory cFactory;
}